#include "head.h"

int main(int argc, char *argv[])
{
    //初始化客户端连接数组
    Connect conn_list[1024];
    memset(conn_list, 0 , sizeof(conn_list));

    //初始化TCP连接
    int socketfd;
    init_tcp(&socketfd, "192.168.222.130", "8080");

    //初始化epoll监听
    int epollfd = epoll_create(1);
    struct epoll_event event;
    event.events = EPOLLIN;
    event.data.fd = socketfd;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, socketfd, &event);

    //初始化集合数组
    Set* set_list[30];
    init_set_list(set_list, 30);
    
    //用于判断是否是第一次进入某个时间段(某一秒)
    //此程序规定: 客户端30s没有发送请求，就将其踢出
    int time_last = time(NULL)%30;

    while(1){
        printf("-----------------\n");
        //epoll监听就绪，时间间隔应当小于等于1秒
        //因为在该程序的超时踢出逻辑中，程序每运行1秒，就需要判断一次是否有客户端超时
        struct epoll_event events[1024];
        int num = epoll_wait(epollfd, events, 1024, 1000);
        //获得现在的时间标记
        int time_now = time(NULL) % 30;
        //如果是第一个从上一秒进入这一秒的循环
        if(time_now != time_last){
            time_last = time_now;
            //踢出超时的客户端：将这个时间标记代表的集合中的连接全部踢出
            //因为程序运行到这里已经经过了30s，此时还在这个集合内的连接都是30s未活跃的连接
            //如果连接有过请求，则这个连接肯定已经从这个集合出去，然后进入了其它集合
            for(int k = 0; k < set_list[time_now]->size; k++){
                //将集合中的元素全部移除
                int close_fd = remove_an_element(set_list[time_now]);
                //取消监听
                epoll_ctl(epollfd, EPOLL_CTL_DEL, close_fd, NULL);
                //关闭连接
                close(close_fd);
                printf("踢出客户端%d\n", close_fd);
                //printf("set%d:\n", time_now);
                //print_set(set_list[time_now]);
            }
        }
        //检查就绪集合
        for(int i = 0; i < num; i++){
            //新的客户端建立连接
            if(events[i].data.fd == socketfd){
                int net_fd = accept(socketfd, NULL, NULL);
                epoll_add_fd(epollfd, net_fd);
                for(int j = 0; j < 1024; j++){
                    if(conn_list[j].flag_unused == 0){
                        (&conn_list[j])->net_fd = net_fd;
                        (&conn_list[j])->is_alive = 1;
                        (&conn_list[j])->tag_active = time(NULL)%30;
                        (&conn_list[j])->flag_unused = 1;
                        break;
                    }
                }
                //新连接进入，将其加入代表当前时间段的集合
                add_element(set_list[time_now], net_fd);
                printf("客户端%d建立连接\n", net_fd);
                printf("set%d:\n", time_now);
                print_set(set_list[time_now]);
            }
            //旧的客户端发送请求
            else{
                int net_fd = events[i].data.fd;
                //更新客户端的活跃时间
                for(int m = 0; m < 1024; m++){
                    if(net_fd == conn_list[m].net_fd){
                        //将这个连接从一个集合移到另一个集合        
                        remove_element(set_list[(&conn_list[m])->tag_active], net_fd); 
                        (&conn_list[m])->tag_active = time_now;
                        add_element(set_list[time_now], net_fd);
                        printf("set%d:\n", time_now);
                        print_set(set_list[time_now]);
                        break;
                    }
                }
                //接收客户端信息
                char buf[1024] = {0};
                int ret_recv = recv(net_fd, buf, sizeof(buf), MSG_WAITALL);
                if(ret_recv == 0){
                    printf("客户端%d主动断开连接\n", net_fd);
                    for(int n = 0; n < 1024; n++){
                        if(net_fd == conn_list[n].net_fd){
                            //客户端主动断开连接，将连接从集合中移除
                            remove_element(set_list[(&conn_list[n])->tag_active], net_fd); 
                            //将客户端连接数组中的该位标记改为未使用，以便其它连接使用
                            (&conn_list[n])->flag_unused = 0;
                            break;
                        }
                    }
                    epoll_ctl(epollfd, EPOLL_CTL_DEL, net_fd, NULL);
                    close(net_fd);
                    //printf("set%d:\n", time_now);
                    //print_set(set_list[time_now]);
                }
                printf("fd %d: %s\n", net_fd, buf);
            }
        }
    }
    close(socketfd);
    return 0;
}

